#pragma once

#include "Socket.hpp"
#include <jsoncpp/json/json.h>

using namespace SocketModule;

// client -> server
class Request
{
public:
    Request(){}
    Request(int x, int y, char oper) 
        : _x(x), _y(y), _oper(oper)
    {}

    std::string Serialize()
    {
        Json::Value root;
        root["x"] = _x;
        root["y"] = _y;
        root["oper"] = _oper; 

        Json::FastWriter writer;
        std::string s = writer.write(root);
        return s;
    }

    // {"x": 10, "y" : 20, "oper" : '+'}
    bool Deserialize(std::string &in)
    {
        // "10" "20" '+' -> 以空格作为分隔符 -> 10 20 '+'
        Json::Value root;
        Json::Reader reader;
        bool ok = reader.parse(in, root);
        if (ok)
        {
            _x = root["x"].asInt();
            _y = root["y"].asInt();
            _oper = root["oper"].asInt();
        }
        return ok;
    }

    int X()
    {
        return _x;
    }

    int Y()
    {
        return _y;
    }

    char Oper()
    {
        return _oper;
    }

    ~Request(){}
private:
    int _x;
    int _y;
    char _oper; // + - * /
};

// server -> client
class Response
{
public:
    Response(){}
    Response(int result, int code) 
        :_result(result), _code(code)
    {}

    std::string Serialize()
    {
        Json::Value root;
        root["result"] = _result;
        root["code"] = _code;

        Json::FastWriter writer;
        return writer.write(root);
    }

    bool Deserialize(std::string &in)
    {
        Json::Value root;
        Json::Reader reader;
        bool ok = reader.parse(in, root);
        if (ok)
        {
            _result = root["result"].asInt();
            _code = root["code"].asInt();
        }
        return ok;
    }

    void SetResult(int res)
    {
        _result = res;
    }

    void SetCode(int code)
    {
        _code = code;
    }

    void ShowResult()
    {
        std::cout << "计算结果是: " << _result << "[" << _code << "]" << std::endl;
    }
    
    ~Response(){}
private:
    int _result; // 运算结果异常，无法区分_result是正常的结果，还是异常值
    int _code; // 0:sucess, 1,2,3,4->不同的运算异常的情况, 这就是一种约定！！！
};

const std::string sep = "\r\n";
using func_t = std::function<Response(Request &req)>;

class Protocol
{
public:
    Protocol() {}
    Protocol(func_t func) 
        :_func(func)
    {}
    ~Protocol() {}
    
    // 封装报文
    std::string Encode(const std::string &jsonstr)
    {
        // len\r\n{"x": 10, "y" : 20, "oper" : '+'}\r\n
        std::string len = std::to_string(jsonstr.size());
        return len + sep + jsonstr + sep;
    }

    // 解析报文
    // 一条完整报文如: 50\r\n{"x": 10, "y" : 20, "oper" : '+'}\r\n
    // read读取到的内容可能如下:
    // 5
    // 50
    // 50\r
    // 50\r\n
    // 50\r\n{"x": 10, "
    // 50\r\n{"x": 10, "y" : 20, "oper" : '+'}\r\n
    // 50\r\n{"x": 10, "y" : 20, "oper" : '+'}\r\n50\r\n{"x": 10, "y" : 20, "ope
    //.....
    // 
    // 1. 判断报文完整性
    // 2. 如果包含至少一个完整请求，提取他，并移除它，方便处理下一个
    bool Decode(std::string &buffer, std::string *package)
    {
        size_t pos = buffer.find(sep);
        if(pos == std::string::npos)
            return false; // 长度不完整，让调用方继续从内核中读取数据
        // 此时得到json字符串的长度
        std::string package_len_str = buffer.substr(0, pos);
        int package_len = std::stoi(package_len_str);
        // 判断buffer是否有一条完整的报文
        int target_len = package_len_str.size() + package_len + sep.size() * 2;
        if(buffer.size() < target_len)
            return false; // buffer中没有一条完整的报文
        // 这时一定拿到了一条完整报文
        *package = buffer.substr(pos + sep.size(), package_len);
        buffer.erase(0, target_len);
        return true;
    }

    void GetRequest(std::shared_ptr<Socket>& socket, InetAddr& client)
    {
        // 从接收缓冲区读取数据
        std::string buffer;
        while(true)
        {
            int n = socket->Recv(&buffer);
            if(n > 0)
            {
                // 解析报文, 提取完整的json字符串，如果不完整，就让服务器继续读取
                std::string json_package;
                while(Decode(buffer, &json_package))
                {
                    LOG(LogLevel::DEBUG) << client.StringAddr() << " 请求: " << json_package;
                    // 将json字符串反序列化
                    Request req;
                    bool ok = req.Deserialize(json_package);
                    if(!ok)
                        continue;
                    // 回调到应用层进行处理
                    Response res = _func(req);

                    // 将结果序列化
                    std::string jsonstr = res.Serialize();

                    // 封装报文
                    std::string message = Encode(jsonstr);

                    socket->Send(message);
                }
            }
            else if (n == 0)
            {
                LOG(LogLevel::INFO) << "client:" << client.StringAddr() << "Quit!";
                break;
            }
            else
            {
                LOG(LogLevel::WARNING) << "client:" << client.StringAddr() << ", recv error";
                break;
            }
        }
    }

    bool GetResponse(std::shared_ptr<Socket> &client, std::string &resp_buff, Response *resp)
    {
        while (true)
        {
            int n = client->Recv(&resp_buff);
            if (n > 0)
            {

                // 成功
                std::string json_package;
                // 1. 解析报文，提取完整的json请求，如果不完整，就让服务器继续读取
                while (Decode(resp_buff, &json_package))
                {
                    // 2. 反序列化
                    resp->Deserialize(json_package);
                }
                return true;
            }
            else if (n == 0)
            {
                std::cout << "server quit " << std::endl;
                return false;
            }
            else
            {
                std::cout << "recv error" << std::endl;
                return false;
            }
        }
    }

    std::string BuildRequestString(int x, int y, char oper)
    {
        // 1. 构建一个完整的请求
        Request req(x, y, oper);

        // 2. 序列化
        std::string json_req = req.Serialize();

        // 3. 添加长度报头
        return Encode(json_req);
    }
private:
    func_t _func;
};